<?php
/**
 * Zhub - A PHP Framework For API Developer
 *
 * This file is part of the Zhub package.
 *
 * (c) YiLong Fan <fantiq@163.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author fanyilong <fantiq@163.com>
 * @copyright 2017 fanyilong. All rights reserved.
 * @package Zhub
 * @date 18-3-5
 */

namespace Zhub\Route;


use Zhub\Route\Exceptions\InvalidRouteDefineClassException;

class Route
{

    private static $collection = null;

    private static $parser = null;

    private static $instance = null;

    private function __construct(string $routeDefine = null)
    {
        self::$parser = new Parser();
        self::$collection = new Collection(self::$parser, $this);
    }

    public static function getInstance(string $routeDefine = null):self
    {
        if (!self::$instance) {
            self::$instance = new self();
            if ($routeDefine) {
                self::$instance->chkRouteDefineClass($routeDefine);
                self::$instance->handle($routeDefine);
            }
        }

        return self::$instance;
    }


    protected function handle(string $routeDefine, Collection $route = null)
    {
        $route = clone ($route ?? self::$collection);
        $prefix = call_user_func([$routeDefine, 'prefix']);
        $route->prefix .= '/' . trim($prefix, '\/');
        $route->pipes = array_merge(
            call_user_func([$routeDefine, 'pipes']),
            $route->pipes
        );
        call_user_func([$routeDefine, 'define'], $route);

        $subRoutes = call_user_func([$routeDefine, 'mount']);
        foreach ($subRoutes as $subRoute) {
            self::chkRouteDefineClass($subRoute);
            $this->handle($subRoute, $route);
        }
    }

    protected static function isRouteDefineClass(string $class):bool
    {
        return in_array(RouteDefine::class, class_implements($class));
    }

    protected static function chkRouteDefineClass(string $class = null)
    {
        if (!$class || !self::isRouteDefineClass($class)) {
            throw new InvalidRouteDefineClassException($class);
        }
    }

    public function match($path)
    {
        return self::$parser->match($path);
    }

    public function routeList()
    {
        return self::$parser->getRoutes();
    }
}